using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Diagnostics;
using Arroguella.Utilities;

namespace Arroguella.Panels
{
    /// <summary>
    /// The panel responsible for displaying messages to the user.
    /// </summary>
    public class MessagePanel : ScreenPanel
    {
        #region Constructor

        public MessagePanel(Game game)
            : base(game)
        {
        }

        #endregion

        #region Events
        #endregion

        #region Methods

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            SetSizeAndShape(0, 0, 15, 10);

            BackgroundColor = Color.Black;

            messages = new Queue<string>();
            messageColors = new Queue<Color>();

            IsLocked = false;

            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here

            base.Update(gameTime);
        }

        /// <summary>
        /// Determines how the message panel is drawn.
        /// </summary>
        public override void Draw(SpriteBatch spriteBatch)
        {
            // Draw the background
            Utils.DrawFilledRectangle(BackgroundColor, SizeAndShape, spriteBatch, Arroguella.GraphicsDevice);

            // Draw the messages starting at the bottom, and going up.
            Vector2 textPosition = new Vector2(SizeAndShape.X + 5, SizeAndShape.Y + SizeAndShape.Height - Font.LineSpacing - 5);
            for (int i = messages.Count -1; i >= 0; i--)
            {
                if (textPosition.Y < SizeAndShape.Y)
                {
                    continue;
                }

                string msg = messages.ElementAt(i);
                Color color = messageColors.ElementAt(i);

                DrawMessage(msg, color, textPosition, spriteBatch);

                textPosition.Y -= Font.LineSpacing;
            }
        }

        /// <summary>
        /// Utility method for drawing a message.
        /// </summary>
        private void DrawMessage(string msg, Color color, Vector2 position, SpriteBatch spriteBatch)
        {
            spriteBatch.DrawString(Font, msg, position, color);
        }

        /// <summary>
        /// Adds a system message.
        /// </summary>
        public void SystemMessage(string msg)
        {
            AddMessage("[SYSTEM] " + msg, SystemMessageColor);
        }

        /// <summary>
        /// Adds a message with a certain color
        /// </summary>
        public void Message(string msg, Color color)
        {
            AddMessage(msg, color);
        }

        /// <summary>
        /// Adds a default message.
        /// </summary>
        /// <param name="msg"></param>
        public void Message(string msg)
        {
            AddMessage(msg, DefaultMessageColor);
        }

        public void ErrorMessage(string msg)
        {
            AddMessage("[ERROR] " + msg, ErrorMessageColor);
        }

        private void AddMessage(string msg, Color color)
        {
            // Safety
            if (string.IsNullOrEmpty(msg))
            {
                return;
            }

            if (IsLocked)
            {
                return;
            }

            Debug.Assert(messages.Count == messageColors.Count);

            if (color == null)
            {
                color = DefaultMessageColor;
            }

            if (messages.Count == MAX_MESSAGES)
            {
                messages.Dequeue();
                Debug.Assert(messages.Count == MAX_MESSAGES - 1);
            }

            if (messageColors.Count == MAX_MESSAGES)
            {
                messageColors.Dequeue();
                Debug.Assert(messageColors.Count == MAX_MESSAGES - 1);
            }

            messages.Enqueue(msg);
            messageColors.Enqueue(color);
        }

        #endregion

        #region Properties

        private Queue<string> messages;

        private Queue<Color> messageColors;

        private static readonly Color DefaultMessageColor = Color.Gainsboro;

        private static readonly Color SystemMessageColor = Color.Gray;

        private static readonly Color ErrorMessageColor = Color.Red;

        /// <summary>
        /// The maximum amount of messages to store in the queue.
        /// </summary>
        private const int MAX_MESSAGES = 64;

        /// <summary>
        /// Whether or not the MessagePanel is locked and prevented from adding further messages.
        /// </summary>
        public bool IsLocked;

        #endregion        
    }
}
